Skip to content

Diagnostics for iOS status-bar tap scroll-to-top (#3589)#4868

Merged
shai-almog merged 6 commits intomasterfrom
simulator-status-bar-tap-diag
May 5, 2026
Merged

Diagnostics for iOS status-bar tap scroll-to-top (#3589)#4868
shai-almog merged 6 commits intomasterfrom
simulator-status-bar-tap-diag

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

@shai-almog shai-almog commented May 5, 2026

Summary

Adds three complementary diagnostics for the iOS status-bar tap scroll-to-top path. The fix from #4857 is in but the reporter still sees no scroll on device, so rather than another sweep these tools let them tell us where the path breaks.

Simulator side: Simulate -> iOS Status Bar Tap menu item

Synthesizes the same (displayWidth/2, 0) tap that scrollViewShouldScrollToTop: dispatches in CodenameOne_GLViewController.m. Pops a dialog with:

  • paintsTitleBarBool / statusBarScrollsUpBool constants
  • The class, UIID and bounds of Form.getResponderAt(displayWidth/2, 0) so the user can see whether the iOS device path would land on the built-in StatusBar button or be blocked by another component
  • An "OK" or "PROBLEM" verdict with likely causes

Then actually fires pointerPressed/pointerReleased so any wired-up scroll-to-top is observable.

iOS device side: Display.getProperty("cn1.iosStatusBarTap.*")

scrollViewShouldScrollToTop: now records each dispatch in static counters surfaced via:

  • cn1.iosStatusBarTap.count -- number of taps received
  • cn1.iosStatusBarTap.lastEpochMillis -- ms-since-epoch of last tap
  • cn1.iosStatusBarTap.lastX / lastY -- coords of last synthesized tap
  • cn1.iosStatusBarTap.proxyInstalled -- whether the proxy view is attached
  • cn1.iosStatusBarTap.diagnostics -- all of the above as a single string

Lets a user run their app on a device, tap the status bar, and inspect the property to distinguish "iOS never delivered the message" from "iOS delivered it but a CodenameOne component intercepted the tap".

Regression coverage: StatusBarTapDiagnosticScreenshotTest in scripts/hellocodenameone

A 2x3 frame grid alternating "scrolled to bottom" and "tap fired -> scrolled to top", with a glass-pane overlay showing the rising tap counter. The tap is fired through a new StatusBarTapDiagnosticNative interface which on iOS calls a factored-out cn1FireStatusBarTap() (the body of scrollViewShouldScrollToTop:) so the real counter and pointer-dispatch path are exercised; other platforms stub the call. The visible scroll is applied explicitly each frame so the screenshot is deterministic across iOS / Android / JavaSE.

Test plan

  • Simulator: open Simulate -> iOS Status Bar Tap on a default iOS-themed form, confirm the dialog reports the StatusBar UIID and the form scrolls to top.
  • Simulator: run on a form without paintsTitleBarBool: true, confirm the warning fires.
  • Simulator: place an overlapping component over the top-center pixel and confirm the dialog reports the overlapping component instead of StatusBar.
  • Device: build an iOS app, tap status bar, confirm Display.getProperty(\"cn1.iosStatusBarTap.count\", \"0\") increments and cn1.iosStatusBarTap.proxyInstalled returns true.
  • CI: StatusBarTapDiagnosticScreenshotTest produces an identical 2x3 grid on iOS, Android, and JavaSE, with the counter rising and the scroll position alternating between bottom / top.

🤖 Generated with Claude Code

Adds a Simulate -> iOS Status Bar Tap menu item that mirrors the
synthesized tap (displayWidth/2, 0) dispatched by
scrollViewShouldScrollToTop: in CodenameOne_GLViewController.m. It
reports the responder at that coordinate plus the relevant theme
constants, so users can verify on the simulator whether the device
tap path would land on the built-in StatusBar button or be blocked
by another component.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 5, 2026

Compared 7 screenshots: 7 matched.
✅ JavaSE simulator integration screenshots matched stored baselines.

Records each scrollViewShouldScrollToTop: dispatch from the
status-bar tap proxy and exposes the counters as
Display.getProperty("cn1.iosStatusBarTap.*") so on-device code can
distinguish "iOS never delivered the scroll-to-top message" from
"iOS delivered it but a CodenameOne component intercepted the tap".

Properties:
  cn1.iosStatusBarTap.count            number of taps received
  cn1.iosStatusBarTap.lastEpochMillis  ms-since-epoch of last tap
  cn1.iosStatusBarTap.lastX            x of last synthesized tap
  cn1.iosStatusBarTap.lastY            y of last synthesized tap
  cn1.iosStatusBarTap.proxyInstalled   is the proxy view attached
  cn1.iosStatusBarTap.diagnostics      all of the above as a string

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog shai-almog changed the title simulator: diagnose iOS status-bar tap scroll-to-top (#3589) Diagnostics for iOS status-bar tap scroll-to-top (#3589) May 5, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 5, 2026

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 5, 2026

Compared 90 screenshots: 90 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 262 seconds

Build and Run Timing

Metric Duration
Simulator Boot 87000 ms
Simulator Boot (Run) 1000 ms
App Install 14000 ms
App Launch 9000 ms
Test Execution 303000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1792.000 ms
Base64 CN1 encode 1802.000 ms
Base64 encode ratio (CN1/native) 1.006x (0.6% slower)
Base64 native decode 1088.000 ms
Base64 CN1 decode 1467.000 ms
Base64 decode ratio (CN1/native) 1.348x (34.8% slower)
Base64 SIMD encode 500.000 ms
Base64 encode ratio (SIMD/native) 0.279x (72.1% faster)
Base64 encode ratio (SIMD/CN1) 0.277x (72.3% faster)
Base64 SIMD decode 557.000 ms
Base64 decode ratio (SIMD/native) 0.512x (48.8% faster)
Base64 decode ratio (SIMD/CN1) 0.380x (62.0% faster)

…3589)

Adds StatusBarTapDiagnosticScreenshotTest plus a StatusBarTapDiagnosticNative
interface (iOS / JavaSE / Android / JS / Win impls). Each frame in the 2x3
grid alternates "scrolled to bottom" / "tap fired -> scrolled to top",
overlaid with a glass pane showing the rising tap counter.

The native interface routes simulateStatusBarTap() through the same path as
scrollViewShouldScrollToTop:; the body is now factored into cn1FireStatusBarTap
in CodenameOne_GLViewController.m so the screenshot test exercises the real
counter+pointer-dispatch on iOS without needing a UIKit status-bar event.
Other platforms stub the call (or fall back to Form.pointerPressed in the
JavaSE impl) and the visible scroll is applied explicitly each frame, so
the screenshot is deterministic across platforms.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 5, 2026

✅ JavaScript-port screenshot tests passed.

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 5, 2026

Compared 90 screenshots: 90 matched.

Native Android coverage

  • 📊 Line coverage: 10.08% (5492/54499 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 7.92% (26952/340279), branch 3.63% (1183/32620), complexity 4.64% (1450/31249), method 8.15% (1190/14604), class 13.55% (266/1963)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 10.08% (5492/54499 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 7.92% (26952/340279), branch 3.63% (1183/32620), complexity 4.64% (1450/31249), method 8.15% (1190/14604), class 13.55% (266/1963)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 924.000 ms
Base64 CN1 encode 126.000 ms
Base64 encode ratio (CN1/native) 0.136x (86.4% faster)
Base64 native decode 861.000 ms
Base64 CN1 decode 793.000 ms
Base64 decode ratio (CN1/native) 0.921x (7.9% faster)
Image encode benchmark status skipped (SIMD unsupported)

shai-almog and others added 3 commits May 5, 2026 07:58
iOS build was failing: cn1FireStatusBarTap calls pointerPressedC and
pointerReleasedC which are defined further down in the file. Add forward
declarations so the function compiles.

Replace the 2x3 animation grid with a side-by-side before/after composite.
Each half is a full-height frame with a glass-pane header showing the
counter, scroll position, and native-interface availability. Reads at a
glance and avoids the JS-port animation-grid decode failures.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The JS port chunk-truncates large screenshot streams. The runner-level
skip list addition wasn't enough (the test still ran on this branch's
CI), so apply the same pattern as AbstractStickyHeaderScreenshotTest
and short-circuit inside runTest with a SKIPPED status log.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
iOS baseline shows native:yes (real cn1FireStatusBarTap counter), Android
shows native:no (stub impl) — both confirm the counter rises 0->3 and the
scroll position flips bottom->top across the before/after composite.
Captured from PR 4868 CI artifacts (ios-ui-tests + emulator-screenshot).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog shai-almog merged commit a79e003 into master May 5, 2026
21 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant